﻿/*
 * Global behavioural attributes. These details are to be exposed through
 * the 'Options' window for the gadget.
 */
var ScreensaverFile = "C:\\Users\\Ben\\AppData\\Local\\Google\\Picasa2\\db3\\saverlist.txt";
var SlideInterval = 0;
var FadeInterval = 0;
var FadeRatio = 0;

/*
 * Global control attributes. These details will be used throughout The
 * control functions to manage the images being displayed.
 */
var CurrentIndex;
var MaximumIndex;
var ImageNameArray;
var CurrentImage = imageOne;
var SlideTimer = null;


/*
 * Main function for the gadget. Starts the slideshow when the
 * gadget is opened.
 */
function onOpen(){
	debug.trace("Executing onOpen");
	initialiseOptions();
	initialiseSlideshow();
	applyOptions();
	runSlideshow();
}

/*
 * Re-apply the configurable options to the control variables
 * and re-start the slideshow.
 */
function onOptionChanged() {
	debug.trace("Executing onOptionChanged");
	applyOptions();
	runSlideshow();
}

/*
 * Initialise the default values for the configurable options.
 */
function initialiseOptions(){
	debug.trace("Executing initialiseOptions");
	options.defaultValue("SlideInterval") = 10000;
	options.defaultValue("FadeInterval") = 1500;
	options.defaultValue("FadeRatio") = 3;
}

/*
 * Apply the configured options to the control variables.
 */
function applyOptions(){
	debug.trace("Executing updateOptions");
	SlideInterval = options("SlideInterval");
	FadeInterval = options("FadeInterval");
	FadeRatio = options("FadeRatio");
	debug.trace("\tSlideInterval: " + SlideInterval);
	debug.trace("\tFadeInterval: " + FadeInterval);
	debug.trace("\tFadeRatio: " + FadeRatio);
}

/*
 * Initialise the slideshow by refreshing the list of images to be displayed,
 * and set the upper index boundary.
 */
function initialiseSlideshow(){
	debug.trace("Executing initialiseSlideshow");
	ImageNameArray = new Array();
	MaximumIndex = loadImageNames(ScreensaverFile, ImageNameArray);
}

/*
 * Load the identifed array with image names read from the identified file.
 * Currently, this method assumes the named file simply contains a 
 * fully-qualified file name on each line.
 */
function loadImageNames(fileName, destArray){
	debug.trace("Executing loadImageNames");
  // Open the file.
	var file = framework.system.filesystem.OpenTextFile(fileName);
	
	// While there are more lines in the file, read the next
  // line and add it to the destination array.
	while (!file.AtEndOfStream){
		destArray.push(file.ReadLine());
	}

	// Close the file handle and return the length of the populated array.
	file.close();
	return destArray.length;
}

/*
 * Start or re-start the slideshow, using the slide interval defined
 * by the configurable "SlideInterval" option.
 */
function runSlideshow(){
	debug.trace("Executing runSlideshow");
	// Stop the slideshow if it is already going.
	if (SlideTimer != null){
		view.clearInterval(SlideTimer)
	}

	// Display the first image, then start the recurring slide interval.
	slideImage();
	SlideTimer = view.setInterval("slideImage()", SlideInterval);
}

/*
 * Core animation function for the slideshow, controls the switching of
 * the displayed image based on the global control variables.
 */ 
function slideImage(){
	debug.trace("Executing slideImage");
	// Grab local references to the UI image currently displayed, and
	// the UI image that is not currently displayed
	var oldImage = CurrentImage;
	var newImage = getOtherImage(oldImage);

	// Initialise the UI image element that is not currently displayed. Make
	// sure it is visible but opaque before filling it with a random image.
	newImage.opacity = 0;
	newImage.visible = true;
	newImage.src = getRandomImageName();
	resizeImage(newImage);

	// Animate the transition from one function to another. The fade is controlled by
	// the global control variables. Experience indicates that fading the old image out
	// faster than the new image is faded in provides a smother transition.
  beginAnimation(function() { setElementOpacity(oldImage); },255,0,(FadeInterval*1)/(FadeRatio*1));
	beginAnimation(function() { setElementOpacity(newImage); },0,255,FadeInterval*1);
  
	// Remember which image is currently displayed.
	CurrentImage = newImage;
}

/*
 * Based on the two UI image elements used to display the slideshow, return 
 * the image that does not match the input parameter.
 */
function getOtherImage(notThisImage){
	debug.trace("Executing getOtherImage");
	if(imageOne != notThisImage)
		return imageOne;
	else
		return imageTwo;
}

/*
 * Retrieve a random image file name from the global control array. This
 * function makes sure that it does not return the same image name as
 * the last time it was called.
 */
function getRandomImageName(){
	debug.trace("Executing getRandomImageName");
	var index = CurrentIndex;

	while(index == CurrentIndex){
		index = Math.floor(Math.random() * (MaximumIndex+1));
	}

	CurrentIndex = index;
	return ImageNameArray[index];
}

/*
 * Based on the orientation and size of the image source, resize the UI image
 * component to fit the image into the core view component.
 */
function resizeImage(image){
	debug.trace("Executing resizeImage");
  if(image.srcheight > view.height || image.srcwidth > view.width){
    if(image.srcheight/view.height > image.srcwidth/view.width){
			// Maximise the space used for portrait pictures.
      image.width=Math.floor(image.srcwidth*(view.height/image.srcheight));
      image.height=view.height;
    }
    else{
			// Maximise the space used for landscape pictures.
      image.height=Math.floor(image.srcheight*(view.width/image.srcwidth));
      image.width=view.width;
    }
  }
  else{
    image.height=image.srcheight;
    image.width=image.srcwidth;
  }

	// Centre the image within the view.
	image.x = Math.floor((view.width - image.width) / 2);
}

/*
 * Event handler for the core animation function. Set the opacity
 * of the identified UI element to the event value.
 */
function setElementOpacity(element) {
  element.opacity = event.value;
}
